import 'dart:async';
import 'dart:io';
import 'dart:ui';

import 'package:device_info_plus/device_info_plus.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';

import '../../config/bt_env_config.dart';
import '../../utils/bt_tool_utils.dart';
import '../store/bt_hive_logon_store.dart';
import 'bt_log_headers.dart';
import 'bt_log_type.dart';

class BtLogManger {
  BtLogManger._internal();

  factory BtLogManger() => _instance;
  static final BtLogManger _instance = BtLogManger._internal();

  static const String tag = "LogManger"; // 日志标签
  static const int limitSize = 20; // 打点任务最多缓存长度
  static int _serialId = 0;
  final List<Map<String, dynamic>> cacheList = [];
  bool _isWaitingForSend = false; // 是否需要延迟上报

  /// 上报日志
  void putLog(BtLogType logType, Map<String, dynamic>? event) async {
    if (logType.logType.isEmpty ||
        logType.subType.isEmpty ||
        logType.behavior.isEmpty ||
        event == null ||
        event.isEmpty) {
      return;
    }
    Map<String, dynamic> itemData =
        await _buildItemData(logType.logType, logType.subType, logType.behavior, event);
    cacheList.insert(0, itemData);
    _sendDelayed();
  }

  /// 延时发送日志
  void _sendDelayed() {
    if (_isWaitingForSend) {
      return;
    }
    _isWaitingForSend = true;
    Timer(const Duration(milliseconds: 2000), () {
      _isWaitingForSend = false;
      _sendLog(false);
    });
  }

  /// 发日志打点
  void _sendLog(bool forceUploadAll) {
    try {
      List<Map<String, dynamic>> sendList = [];
      if (cacheList.isEmpty) {
        return;
      } else if (cacheList.length >= limitSize && !forceUploadAll) {
        sendList.addAll(cacheList.sublist(0, limitSize));
        cacheList.removeRange(0, limitSize);
      } else {
        sendList.addAll(cacheList);
        cacheList.clear();
      }
      _doUpload(sendList, true);
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }
  }

  /// 立马发送日志
  void putLogRightNow(BtLogType logType, Map<String, dynamic>? event) async {
    if (logType.logType.isEmpty ||
        logType.subType.isEmpty ||
        logType.behavior.isEmpty ||
        event == null ||
        event.isEmpty) {
      return;
    }
    Map<String, dynamic> itemData =
        await _buildItemData(logType.logType, logType.subType, logType.behavior, event);
    List<Map<String, dynamic>> list = [];
    list.add(itemData);

    _doUpload(list, false);
  }

  /// 执行上传
  Future<void> _doUpload(List<Map<String, dynamic>> sendList, bool isContinue) async {
    if (kDebugMode) {
      print(sendList);
    }
    var options = BaseOptions(
        contentType: "application/json",
        receiveTimeout: const Duration(seconds: 30),
        connectTimeout: const Duration(seconds: 30));
    await _buildLogHeader(options);
    var dio = Dio(options);
    dio.post(logApiBaseUrl + logLiveChat, data: sendList).then((value) {
      if (isContinue) {
        _sendDelayed();
      }
      if (kDebugMode) {
        print("😈$value");
      }
    });
  }

  _buildLogHeader(BaseOptions options) async {
    String deviceId = await getDeviceId();
    var data = await BtHiveLogonStore().getData();
    DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
    var packageInfo = await PackageInfo.fromPlatform();
    String version = packageInfo.version;
    String bundleId = packageInfo.packageName;
    String buildNumber = packageInfo.buildNumber;
    String accessToken = data?.token ?? '';
    options.headers['Authorization'] = 'Bearer$accessToken';
    options.headers['device-id'] = deviceId;
    if (Platform.isAndroid) {
      AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
      options.headers['model'] = androidInfo.model;
      options.headers['platform'] = 'Android';
    } else if (Platform.isIOS) {
      IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
      options.headers['model'] = iosInfo.model;
      options.headers["platform"] = "iOS";
    }
    options.headers['pkg'] = bundleId;
    options.headers['ver'] = version;
    options.headers['p_ver'] = buildNumber; // build number
    options.headers['kst'] = '1'; // 固定传1
    options.headers['sys_lan'] = const Locale.fromSubtags().languageCode;
    options.headers['lang'] = const Locale.fromSubtags().languageCode;
  }

  Future<Map<String, dynamic>> _buildItemData(
      String logType, String subType, String behavior, Map<String, dynamic>? event) async {
    String deviceId = await getDeviceId();
    var data = await BtHiveLogonStore().getData();
    DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
    var packageInfo = await PackageInfo.fromPlatform();
    String buildNumber = packageInfo.buildNumber;
    String version = packageInfo.version;
    String bundleId = packageInfo.packageName;
    String model = '';
    String platform = '';
    String platformVersion = '';

    if (Platform.isAndroid) {
      AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
      platform = 'Android';
      model = androidInfo.model;
      platformVersion = androidInfo.version.sdkInt.toString();
    } else if (Platform.isIOS) {
      IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
      platform = "iOS";
      model = iosInfo.model;
      platformVersion = iosInfo.systemVersion;
    }
    String launcherId = stringToMd5('${DateTime.now().millisecondsSinceEpoch}$deviceId');

    Map<String, dynamic> itemData = {};
    itemData[BtLogHeaders.logData] = [event];
    itemData[BtLogHeaders.logLogType] = logType;
    itemData[BtLogHeaders.logSubtype] = subType;
    itemData[BtLogHeaders.logBehavior] = behavior;
    itemData[BtLogHeaders.logDeviceId] = deviceId;
    itemData[BtLogHeaders.logUserId] = data?.userId ?? '';
    itemData[BtLogHeaders.logPkg] = bundleId;
    itemData[BtLogHeaders.logChnId] = '';
    itemData[BtLogHeaders.logVer] = version;
    itemData[BtLogHeaders.logPlatform] = platform;
    itemData[BtLogHeaders.logModel] = model;
    itemData[BtLogHeaders.logPVer] = buildNumber;
    itemData[BtLogHeaders.logLanId] = launcherId;
    itemData[BtLogHeaders.logSecId] = _serialId++;
    itemData[BtLogHeaders.logSysLan] = const Locale.fromSubtags().languageCode;
    itemData[BtLogHeaders.logCountry] = const Locale.fromSubtags().languageCode;
    itemData["platform_ver"] = platformVersion;
    itemData["is_in_bg"] = false;
    itemData["is_anchor"] = false;
    itemData["client_type"] = "common";
    itemData["bizver"] = "";
    itemData["tm"] = DateTime.now().millisecondsSinceEpoch;
    return itemData;
  }
}
